home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1998 November / Freeware November 1998.img / dist / fw_mh.idb / usr / freeware / src / mh-6.8.3 / uip / sendmail.c.z / sendmail.c
C/C++ Source or Header  |  1997-09-09  |  14KB  |  576 lines

  1. /* sendmail.c - */
  2. #ifndef    lint
  3. static char Id[] = "$Id: sendmail.c,v 1.9 1992/11/24 18:37:01 jromine Exp $";
  4. #endif
  5. /*
  6.  **  A Sendmail fake.
  7.  *
  8.  * Contributed by Scott Erickson <erickson@ics.uci.edu>
  9.  */
  10. /* Include files glommed from post.c */
  11.  
  12. #include "../h/mh.h"
  13. #include "../h/addrsbr.h"
  14. #include "../h/aliasbr.h"
  15. #include "../h/dropsbr.h"
  16. #include "../zotnet/tws.h"
  17. #ifndef MMDFMTS
  18. #include <ctype.h>
  19. #include <errno.h>
  20. #include <setjmp.h>
  21. #include <stdio.h>
  22. #include <sys/types.h>
  23. #else   MMDFMTS
  24. #include "../mts/mmdf/util.h"
  25. #include "../mts/mmdf/mmdf.h"
  26. #endif  MMDFMTS
  27. #include "../zotnet/mts.h"
  28. #ifdef  MHMTS
  29. #ifndef V7
  30. #include <sys/ioctl.h>
  31. #endif  not V7
  32. #include <sys/stat.h>
  33. #endif  MHMTS
  34. #ifdef  SENDMTS
  35. #include "../mts/sendmail/smail.h"
  36. #undef  MF
  37. #endif  SENDMTS
  38. #include <signal.h>
  39. #ifdef LOCALE
  40. #include    <locale.h>
  41. #endif
  42.  
  43. char    *SMTPSRVR = "smtpsrvr";
  44.  
  45. char    msgfname[50];    /* name of message file */
  46. char    *FullName;    /* sender's full name */
  47. char    *from;        /* sender's mail address */
  48. int    verbose;
  49. int    verify;
  50. int    extract;
  51. int    dodist;
  52. int    rewritefrom;
  53. int    status;        /* return value from procedures */
  54. static int childid;    /* id from smtp child process */
  55. TYPESIG    die();
  56. long    lclock = 0L;    /* the time we started (more or less) */
  57.  
  58.  
  59. FILE *fp;        /* file pointer for message file */
  60. extern FILE *tmpfile();
  61.  
  62. static struct swit switches[] = {
  63. #define ARPASW    0
  64.     "ba", -2,
  65. #define DAEMONSW  1
  66.     "bd", -2,
  67. #define INITALSW  2
  68.     "bi", -2,
  69. #define DELIVSW   3
  70.     "bm", -2,
  71. #define QSUMSW    4
  72.     "bp", -2,
  73. #define SMTPSW    5
  74.     "bs", -2,
  75. #define ADRTSTSW  6
  76.     "bt", -2,
  77. #define ADRVRFSW  7
  78.     "bv", -2,
  79. #define CFGFRZSW  8
  80.     "bz", -2,
  81. #define ALTCFGSW  9
  82.     "C", -1,
  83. #define DBGVALSW 10
  84.     "d", -1,
  85. #define FULLSW   11
  86.     "F", -1,
  87. #define FROMSW   12
  88.     "f", -1,
  89. #define HOPCNTSW 13
  90.     "h", -1,
  91. #define MSGIDSW  14
  92.     "M", -1,
  93. #define NOALISW  15
  94.     "n", -1,
  95. #define QTIMESW  16
  96.     "q", -1,
  97. #define OBSFRMSW 17
  98.     "r", -1,
  99. #define EXTHDRSW 18
  100.     "t", -1,
  101. #define VERBSW     19
  102.     "v", -1,
  103. #define ALTALISW 20
  104.     "oA", -2,
  105. #define NOCONSW   21
  106.     "oc", -2,
  107. #define DLVMODSW 22
  108.     "od", -2,
  109. #define NEWALISW 23
  110.     "oD", -2,
  111. #define ERRMODSW 24
  112.     "oe", -2,
  113. #define TMPMODSW 25
  114.     "oF", -2,
  115. #define UFROMSW  26
  116.     "of", -2,
  117. #define GIDSW    27
  118.     "og", -2,
  119. #define HLPFILSW 28
  120.     "oH", -2,
  121. #define NODOTSW  29
  122.     "oi", -2,
  123. #define LOGLEVSW 30
  124.     "oL", -2,
  125. #define MEOKSW   31
  126.     "om", -2,
  127. #define OLDHDRSW 32
  128.     "oo", -2,
  129. #define QDIRSW   33
  130.     "oQ", -2,
  131. #define RTMOUTSW 34
  132.     "or", -2,
  133. #define SFILESW  35
  134.     "oS", -2,
  135. #define QMSGSW   36
  136.     "os", -2,
  137. #define MTMOUTSW 37
  138.     "oT", -2,
  139. #define TZSW     38
  140.     "ot", -2,
  141. #define UIDSW    39
  142.     "ou", -2,
  143.     
  144.     NULL, 0
  145.     };
  146.  
  147. #if !defined(POSIX) && !defined(_POSIX_SOURCE)
  148. extern char *mktemp();
  149. #endif
  150.  
  151. static void removemsg();
  152. static int  isheader(), sendfile();
  153.  
  154. /*ARGSUSED*/
  155. main (argc, argv)
  156. int    argc;
  157. char **argv;
  158. {
  159.     register char *cp;
  160.     char **argp = argv + 1;
  161.     
  162. #ifdef LOCALE
  163.     setlocale(LC_ALL, "");
  164. #endif
  165.     invo_name = r1bindex (argv[0], '/');
  166.     mts_init(argv[0]);
  167.     
  168.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  169.     (void) signal(SIGINT, die);
  170.     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  171.     (void) signal(SIGHUP, die);
  172.     (void) signal(SIGTERM, die);
  173.     (void) signal(SIGPIPE, die);
  174.     
  175.     FullName = getfullname();
  176.     from = adrsprintf(NULLCP,NULLCP);
  177.     (void) time (&lclock);
  178.     
  179.     while ( (cp = *argp) &&  *cp == '-' ) {
  180.     argp++;
  181.     switch (smatch ( ++cp, switches )) {
  182.     case ARPASW:    /* smtp on stdin */
  183.     case SMTPSW:    /* smtp on stdin */
  184.         smtp();
  185.         exit(98);    /* should never happen */
  186.         
  187.     case DELIVSW:    /* just send mail */
  188.         continue;
  189.         
  190.     case ADRVRFSW:    /* verify mode */
  191.         verify = 1;
  192.         continue;
  193.         
  194.     case FROMSW:    /* from address */
  195.     case OBSFRMSW:    /* obsolete -f flag */
  196.         if (*(++cp) == '\0' &&
  197.         (!(cp = *argp++) || *cp == '-'))
  198.         adios (NULLCP, "missing argument to %s", argp[-2]);
  199.         /* At this point, cp points to the from name */
  200.         if (rewritefrom) {
  201.         adios (NULLCP, "More than one \"from\" person");
  202.         continue;
  203.         }
  204.         from = cp;
  205.         rewritefrom = 1;
  206.         continue;
  207.         
  208.     case EXTHDRSW:    /* read recipients from message */
  209.         extract = 1;
  210.         continue;
  211.         
  212.     case VERBSW:    /* give blow-by-blow description */
  213.         verbose = 1;
  214.         continue;
  215.         
  216.         /* These switches have no args. */
  217.     case QMSGSW:    /* always queue the message */
  218.     case DAEMONSW:    /* run as a daemon & wait for SMTP */
  219.     case INITALSW:    /* initialize the alias database */
  220.     case QSUMSW:    /* print summary of mail queue */
  221.     case ADRTSTSW:    /* test the addresses to debug config file */
  222.     case CFGFRZSW:    /* create the configuration freeze file */
  223.     case NOALISW:    /* do not do aliasing */
  224.     case NOCONSW:    /* do not initiate immediate host connection */
  225.     case NEWALISW:    /* run newaliases to rebuild db */
  226.     case UFROMSW:    /* save UNIX-style From lines at front of msg*/
  227.     case NODOTSW:    /* dots on line are not msg terminators */
  228.     case MEOKSW:    /* ok to send to me if I'm in an alias */
  229.     case OLDHDRSW:    /* msg may have old-style headers */
  230.         continue;
  231.         
  232.         /* These switches have string args. */
  233.     case ALTALISW:    /* use alternate alias file */
  234.     case ALTCFGSW:    /* use alternate configuration file */
  235.     case DBGVALSW:    /* set the debug value */
  236.     case FULLSW:    /* set full name */
  237.     case MSGIDSW:    /* try to deliver queued msg with msg-id */
  238.     case QTIMESW:    /* interval between queue passes */
  239.     case DLVMODSW:    /* set the delivery mode */
  240.     case ERRMODSW:    /* set the error mode */
  241.     case TMPMODSW:    /* the mode to use when creating tmp files */
  242.     case HLPFILSW:    /* the SMTP help file */
  243.     case QDIRSW:    /* directory into which to queue messages */
  244.     case RTMOUTSW:    /* timeout on reads */
  245.     case SFILESW:    /* save statistics in this file */
  246.     case MTMOUTSW:    /* timeout on messages in the queue */
  247.     case TZSW:    /* set the name of the timezone */
  248.         if (*(++cp) == '\0' &&
  249.         (!(cp = *argp++) || *cp == '-'))
  250.         adios (NULLCP, "missing argument to %s", argp[-2]);
  251.         /* At this point, cp points to the argument */
  252.         continue;    /* Ignore */
  253.         
  254.         /* These switches have numeric args. */
  255.     case HOPCNTSW:    /* hop count */
  256.     case GIDSW:    /* gid when calling mailers */
  257.     case LOGLEVSW:    /* the log level */
  258.     case UIDSW:    /* uid when calling mailers */
  259.         if (*(++cp) == '\0' &&
  260.         (!(cp = *argp++) || *cp == '-'))
  261.         adios (NULLCP, "missing argument to %s", argp[-2]);
  262.         /* At this point, cp points to the numeric arg */
  263.         if (!isdigit(*cp))
  264.         adios (NULLCP, "non-numeric argument to %s", argp[-2]);
  265.         continue;    /* Ignore */
  266.     }
  267.     }
  268.     
  269.     (void) setuid(getuid());
  270.     
  271.     if (verify && extract)
  272.     adios (NULLCP, "mode not supported on header components");
  273.     
  274.     if (*argp == NULL && !extract)
  275.     adios (NULLCP, "usage: /usr/lib/sendmail [flags] addr...");
  276.     
  277.     strcpy (msgfname, "/tmp/sendmhXXXXXX");
  278.     if ( mktemp(msgfname) == NULL )
  279.     adios (msgfname, "can't create msg file ");
  280.     
  281.     if ( (fp = fopen(msgfname,"w") ) == NULL ) {
  282.     adios (msgfname, "error opening ");
  283.     }
  284.     
  285.     doheader(argp);
  286.     if ( verify ) {
  287.     (void) fclose(fp);
  288.     status = doverify();
  289.     removemsg();
  290.     exit ( status ) ;
  291.     }
  292.     dobody();
  293.     status = sendfile();
  294.     removemsg();
  295.     exit ( status );
  296. }
  297.  
  298. static void removemsg()
  299. {
  300.   if ( unlink(msgfname) != 0 )
  301.       perror("unlink");
  302. }
  303.  
  304. doheader(argp)
  305. char **argp;
  306. {
  307.     char    line[BUFSIZ];
  308.     int        gotdate, gotfrom, gotsender, gotto;
  309.     
  310.     /* if we're not extracting the headers from the message, then we
  311.      * need to check to see if we need to do a "send" or a "dist".
  312.      */
  313.     
  314.     if ( !extract ) {
  315.     /* If we're doing a verify, just create a "To:" header. */
  316.     if ( ! verify ) {
  317.         gotdate = gotfrom = gotto = gotsender = dodist = 0;
  318.         while (fgets (line, BUFSIZ, stdin) != NULL) {
  319.         if (line[0] == '\n')        /* end of header */
  320.             break;
  321.         if ( !isheader(line) )
  322.             break;
  323.  
  324.         /* if any of the following headers are present, then we
  325.          * want to do a dist.
  326.          */
  327.         if ( !gotdate && uprf(line, "date") )
  328.             gotdate = dodist = 1;
  329.  
  330.         else if ( !gotto && (uprf(line, "to") || uprf(line, "cc")) )
  331.             gotto = dodist = 1;
  332.  
  333.         else if ( uprf(line, "message-id") )
  334.             dodist = 1;
  335.  
  336.         else if ( !gotsender && uprf(line, "sender") )
  337.             gotsender = dodist = 1;
  338.         
  339.         else if ( uprf ( line, "resent-" ) ) {
  340.             dodist = 1;
  341.             (void) fputs("Prev-", fp);
  342.         }
  343.         
  344.         /* See if we are re-writing the from line */
  345.         if ( uprf(line, "from") ) {
  346.             gotfrom = 1;
  347.             if ( rewritefrom )
  348.             dofrom();
  349.             else
  350.             (void) fputs(line,fp);
  351.         }
  352.         else
  353.             (void) fputs(line,fp);
  354.         }
  355.     }
  356.     /* Now, generate a "to" line.  The first line is easy.
  357.      * Write the rest of the lines with a newline/tab so that we
  358.      * don't accidentally write a line that's too long to be parsed
  359.      * by post.
  360.      */
  361.     (void) fprintf (fp, "%sTo: %s", (dodist ? "Resent-" : "" ), *argp++);
  362.     while ( *argp )
  363.         (void) fprintf ( fp, ",\n\t%s", *argp++ );
  364.     (void) fputs("\n",fp);
  365.  
  366.     /* If we're doing a dist, we must have a "Date:" and "From:" field.
  367.      */
  368.     if ( dodist ) {
  369.         if ( !gotdate )
  370.         (void) fprintf (fp, "Date: %s\n", dtime (&lclock));
  371.         if ( !gotfrom )
  372.         dofrom();
  373.     }
  374. #ifdef    MMDFI            /* sigh */
  375.     if ( !gotsender )
  376.         (void) fprintf (fp, "Sender: %s\n", from);
  377. #endif    MMDFI
  378.     } else {    /* we're verifying, so just pass everything through */
  379.     while (fgets (line, BUFSIZ, stdin) != NULL) {
  380.         if (line[0] == '\n')        /* end of header */
  381.         break;
  382.         
  383.         if ( rewritefrom && uprf(line, "from"))
  384.         dofrom();
  385.         else
  386.         (void) fputs(line,fp);
  387.     }
  388.     }
  389.     /* At this point, line is either a newline (end of header) or the
  390.      * first line of the body (poorly formatted message).  If line
  391.      * contains a line of body from a poorly formatted message, then
  392.      * print a newline to separate the header correctly, then print
  393.      * the body line.
  394.      */
  395.     if ( line[0] != '\n' )    /* i.e. a "body" line */
  396.     (void) fputc('\n', fp);
  397.     (void) fputs(line, fp);
  398. }
  399.  
  400. static int isheader(s)
  401. char *s;
  402. {
  403.     register char *cp;
  404.  
  405.     /* If the first character is a space, assume a continuation of a header */
  406.     if ( isspace(*s) )
  407.     return 1;
  408.  
  409.     /* If there's no ':', it's not a header */
  410.     if ( (cp = index(s,':')) == NULL )
  411.     return 0;
  412.  
  413.     /* If there's a space between BOL and ':', it's not a header */
  414.     while ( s < cp ) {
  415.     if ( isspace(*s) )
  416.         return 0;
  417.     s++;
  418.     }
  419.     return 1;
  420. }
  421.  
  422. /* This procedure does the verify and returns the status */
  423. doverify() {
  424.     char *command, buf[BUFSIZ], *bp;
  425.     FILE *verfp, *popen();
  426.     
  427.     /* set up the command line for post */
  428.     if ( (command = (char *)malloc((strlen(postproc) +
  429.                     strlen(" -whom -check -verbose ") +
  430.                     strlen(msgfname) + 1 )*sizeof(char)))
  431.     == NULL ) {
  432.     perror("malloc");
  433.     return NOTOK;
  434.     }
  435.     
  436.     (void) strcpy(command,postproc);
  437.     (void) strcat(command," -whom -check ");
  438.     if ( verbose )
  439.     (void) strcat(command, "-verbose " );
  440.     (void) strcat(command, msgfname);
  441.     
  442.     /* open up the pipe */
  443.     if ( (verfp = popen(command,"r")) == NULL )
  444.     return NOTOK;
  445.     
  446.     while ( fgets(buf, BUFSIZ, verfp) != NULL )
  447.     /* sendmail returns:
  448.      *   address:  result
  449.      * so we need to strip the extra post headers.
  450.      */
  451.     if ( verbose ) {
  452.         bp = buf;
  453.         while (isspace(*bp))
  454.         bp++;
  455.         if ( *bp != '-' )
  456.         (void) fputs(bp,stdout);
  457.     }
  458.     
  459.     /* return the error status of post */
  460.     return( pclose(verfp) >> 8 );
  461. }
  462.  
  463. static int sendfile()
  464. {
  465.     char *command, buf[BUFSIZ];
  466.     FILE *verfp, *popen();
  467.     
  468.     /* set up the command line for post */
  469.     if ( (command = (char *)malloc((strlen(postproc) +
  470.                     strlen(" -dist -verbose ") +
  471.                     strlen(msgfname) + 1 )*sizeof(char)))
  472.     == NULL ) {
  473.     perror("malloc");
  474.     return NOTOK;
  475.     }
  476.     
  477.     (void) strcpy(command,postproc);
  478.     (void) strcat(command," ");
  479.     if ( verbose )
  480.     (void) strcat(command, "-verbose " );
  481.     if ( dodist )
  482.     (void) strcat(command, "-dist " );
  483.     (void) strcat(command, msgfname);
  484.     
  485.     /* open up the pipe */
  486.     if ( (verfp = popen(command,"r")) == NULL )
  487.     return NOTOK;
  488.     
  489.     while ( fgets(buf, BUFSIZ, verfp) != NULL )
  490.     (void) fputs(buf,stdout);
  491.  
  492.     /* return the error status of post */
  493.     return( pclose(verfp) >> 8 );
  494. }
  495.  
  496. dofrom() {
  497.     char    line[128];
  498.     
  499.     if (FullName)
  500.     (void) sprintf(line, "From: %s <%s>\n", FullName, from);
  501.     else
  502.     (void) sprintf(line, "From: %s\n", from);
  503.     (void) fputs(line, fp);
  504. }
  505.  
  506. dobody() {
  507.     register int    i;
  508.     char    buffer[BUFSIZ];
  509.     
  510.     while (!feof (stdin) && !ferror (stdin) &&
  511.        (i = fread (buffer, sizeof (char), sizeof (buffer), stdin)) > 0)
  512.     if (fwrite (buffer, sizeof (char), i , fp) != i )
  513.         adios (NULLCP, "Problem writing body");
  514.     
  515.     if (ferror (stdin))
  516.     adios (NULLCP, "Problem reading body");
  517.     
  518.     if ( fclose(fp) != 0 )
  519.     adios (NULLCP, "problem ending submission");
  520. }
  521.  
  522. TYPESIG silentdie();
  523.  
  524. smtp()
  525. {
  526.     int sd,len;
  527.     char buf[BUFSIZ], response[BUFSIZ];
  528.  
  529.     if ((sd = client(NULLCP, "tcp", "smtp", 0, response)) == NOTOK)
  530.     adios (NULLCP, "cannot open smtp client process");
  531.  
  532.     (void) signal(SIGCHLD, silentdie);
  533.  
  534.     switch ((childid = fork())) {
  535.     case NOTOK:
  536.         adios (NULLCP, "unable to fork smtp process");
  537.     
  538.     case OK:    /* i.e. child */
  539.         (void) dup2(sd,0);
  540.         break;
  541.  
  542.     default:    /* i.e. parent */
  543.         (void) dup2(sd,1);
  544.         break;
  545.     }
  546.     while ( (len = read(0, buf, BUFSIZ)) > 0)
  547.     (void) write (1, buf, len);
  548.  
  549.     if (childid)
  550.     (void) kill(childid, SIGHUP);
  551.  
  552.     exit(9);
  553. }
  554.  
  555. /* ARGSUSED */
  556. TYPESIG    die(sig)
  557. int sig;
  558. {
  559.     if (fp) {
  560.     (void) fclose(fp);
  561.     (void) unlink(msgfname);
  562.     }
  563.     if (sig != SIGHUP)
  564.     (void) fprintf(stderr, "sendmail: dying from signal %d\n", sig);
  565.     exit(99);
  566. }
  567.  
  568. /* ARGSUSED */
  569.  
  570. TYPESIG    silentdie(sig)
  571. int sig;
  572. {
  573.     pidwait (childid, OK);
  574.     exit(0);
  575. }
  576.